/*
 * @(#) $Header$
 *
 * Copyright (C) 2010  Daniel Léonard
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 */

package ca.forklabs.crypto.md;

import ca.forklabs.crypto.md.RIPEMDFamily;

/**
 * This class embodies the algorithm for the message digest RIPEMD320 according to
 * <a target="external" href="http://www.esat.kuleuven.ac.be/~bosselae/ripemd160.html">
 * Antoon Bosselaers's page</a>. It is more elegant to get an instance with the factory method
 * in class {@link java.security.MessageDigest} :
 * <blockquote>
 * <code>MessageDigest ripemd320 = MessageDigest.getInstance(Forklabs.RIPE_MD_320, Forklabs.NAME);</code>
 * </blockquote>
 *
 * @author   <a href="mailto:forklabs at gmail.com?subject=ca.forklabs.crypto.md.RIPEMD320">Daniel Léonard</a>
 * @version $Revision$
 * @see      ca.forklabs.crypto.Forklabs
 */
public class RIPEMD320 extends RIPEMDFamily {

//---------------------------
// Class variables
//---------------------------

   /** The name of this message digest. */
   @SuppressWarnings("nls")
   public static final String NAME = "RIPEMD320";

   /** The length in bytes of the digest. */
   public static final int DIGEST_LEN = 40;

   /** The size of the internal state in block of 32 bits. */
   public static final int STATE_LEN = 10;


//----------------------------
// Constructor
//----------------------------

   /**
    * Constructor.
    */
   public RIPEMD320() {
      super(RIPEMD320.NAME, RIPEMD320.DIGEST_LEN, RIPEMD320.STATE_LEN);
      this.coreInit();
      }


//----------------------------
// RIPEMD320 scrambling methods
//----------------------------

   private static int FF(int a, int b, int c, int d, int e, int x, int s) {
      int word = a + (b ^ c ^ d) + x;
      return AbstractBlockMessageDigest.rotateLeft(word, s) + e;
      }

   private static int GG(int a, int b, int c, int d, int e, int x, int s) {
      int word = a + ((b & c) | (~b & d)) + x + 0x5a827999;
      return AbstractBlockMessageDigest.rotateLeft(word, s) + e;
      }

   private static int HH(int a, int b, int c, int d, int e, int x, int s) {
      int word = a + ((b | ~c) ^ d) + x + 0x6ed9eba1;
      return AbstractBlockMessageDigest.rotateLeft(word, s) + e;
      }

   private static int II(int a, int b, int c, int d, int e, int x, int s) {
      int word = a + ((b & d) | (c & ~d)) + x + 0x8f1bbcdc;
      return AbstractBlockMessageDigest.rotateLeft(word, s) + e;
      }

   private static int JJ(int a, int b, int c, int d, int e, int x, int s) {
      int word = a + (b ^ (c | ~d)) + x + 0xa953fd4e;
      return AbstractBlockMessageDigest.rotateLeft(word, s) + e;
      }

   private static int FFF(int a, int b, int c, int d, int e, int x, int s) {
      int word = a + (b ^ c ^ d) + x;
      return AbstractBlockMessageDigest.rotateLeft(word, s) + e;
      }

   private static int GGG(int a, int b, int c, int d, int e, int x, int s) {
      int word = a + ((b & c) | (~b & d)) + x + 0x7a6d76e9;
      return AbstractBlockMessageDigest.rotateLeft(word, s) + e;
      }

   private static int HHH(int a, int b, int c, int d, int e, int x, int s) {
      int word = a + ((b | ~c) ^ d) + x + 0x6d703ef3;
      return AbstractBlockMessageDigest.rotateLeft(word, s) + e;
      }

   private static int III(int a, int b, int c, int d, int e, int x, int s) {
      int word = a + ((b & d) | (c & ~d)) + x + 0x5c4dd124;
      return AbstractBlockMessageDigest.rotateLeft(word, s) + e;
      }

   private static int JJJ(int a, int b, int c, int d, int e, int x, int s) {
      int word = a + (b ^ (c | ~d)) + x + 0x50a28be6;
      return AbstractBlockMessageDigest.rotateLeft(word, s) + e;
      }


//----------------------------
// RIPEMD320 core methods
//----------------------------

   @Override
   protected void coreTransform() {
      int[] state = this.getState();
      int aa = state[0];
      int bb = state[1];
      int cc = state[2];
      int dd = state[3];
      int ee = state[4];
      int aaa = state[5];
      int bbb = state[6];
      int ccc = state[7];
      int ddd = state[8];
      int eee = state[9];

      byte[] buffer = this.getBuffer();
      int x_0  = AbstractBlockMessageDigest.makeInt(buffer, 3,  2,  1,  0);
      int x_1  = AbstractBlockMessageDigest.makeInt(buffer, 7,  6,  5,  4);
      int x_2  = AbstractBlockMessageDigest.makeInt(buffer, 11, 10, 9,  8);
      int x_3  = AbstractBlockMessageDigest.makeInt(buffer, 15, 14, 13, 12);
      int x_4  = AbstractBlockMessageDigest.makeInt(buffer, 19, 18, 17, 16);
      int x_5  = AbstractBlockMessageDigest.makeInt(buffer, 23, 22, 21, 20);
      int x_6  = AbstractBlockMessageDigest.makeInt(buffer, 27, 26, 25, 24);
      int x_7  = AbstractBlockMessageDigest.makeInt(buffer, 31, 30, 29, 28);
      int x_8  = AbstractBlockMessageDigest.makeInt(buffer, 35, 34, 33, 32);
      int x_9  = AbstractBlockMessageDigest.makeInt(buffer, 39, 38, 37, 36);
      int x_10 = AbstractBlockMessageDigest.makeInt(buffer, 43, 42, 41, 40);
      int x_11 = AbstractBlockMessageDigest.makeInt(buffer, 47, 46, 45, 44);
      int x_12 = AbstractBlockMessageDigest.makeInt(buffer, 51, 50, 49, 48);
      int x_13 = AbstractBlockMessageDigest.makeInt(buffer, 55, 54, 53, 52);
      int x_14 = AbstractBlockMessageDigest.makeInt(buffer, 59, 58, 57, 56);
      int x_15 = AbstractBlockMessageDigest.makeInt(buffer, 63, 62, 61, 60);

      AbstractBlockMessageDigest.zeroize(buffer);

      int t;
   // round 1
      aa = RIPEMD320.FF(aa, bb, cc, dd, ee, x_0 , 11); cc = AbstractBlockMessageDigest.rotateLeft(cc, 10);
      ee = RIPEMD320.FF(ee, aa, bb, cc, dd, x_1 , 14); bb = AbstractBlockMessageDigest.rotateLeft(bb, 10);
      dd = RIPEMD320.FF(dd, ee, aa, bb, cc, x_2 , 15); aa = AbstractBlockMessageDigest.rotateLeft(aa, 10);
      cc = RIPEMD320.FF(cc, dd, ee, aa, bb, x_3 , 12); ee = AbstractBlockMessageDigest.rotateLeft(ee, 10);
      bb = RIPEMD320.FF(bb, cc, dd, ee, aa, x_4 ,  5); dd = AbstractBlockMessageDigest.rotateLeft(dd, 10);
      aa = RIPEMD320.FF(aa, bb, cc, dd, ee, x_5 ,  8); cc = AbstractBlockMessageDigest.rotateLeft(cc, 10);
      ee = RIPEMD320.FF(ee, aa, bb, cc, dd, x_6 ,  7); bb = AbstractBlockMessageDigest.rotateLeft(bb, 10);
      dd = RIPEMD320.FF(dd, ee, aa, bb, cc, x_7 ,  9); aa = AbstractBlockMessageDigest.rotateLeft(aa, 10);
      cc = RIPEMD320.FF(cc, dd, ee, aa, bb, x_8 , 11); ee = AbstractBlockMessageDigest.rotateLeft(ee, 10);
      bb = RIPEMD320.FF(bb, cc, dd, ee, aa, x_9 , 13); dd = AbstractBlockMessageDigest.rotateLeft(dd, 10);
      aa = RIPEMD320.FF(aa, bb, cc, dd, ee, x_10, 14); cc = AbstractBlockMessageDigest.rotateLeft(cc, 10);
      ee = RIPEMD320.FF(ee, aa, bb, cc, dd, x_11, 15); bb = AbstractBlockMessageDigest.rotateLeft(bb, 10);
      dd = RIPEMD320.FF(dd, ee, aa, bb, cc, x_12,  6); aa = AbstractBlockMessageDigest.rotateLeft(aa, 10);
      cc = RIPEMD320.FF(cc, dd, ee, aa, bb, x_13,  7); ee = AbstractBlockMessageDigest.rotateLeft(ee, 10);
      bb = RIPEMD320.FF(bb, cc, dd, ee, aa, x_14,  9); dd = AbstractBlockMessageDigest.rotateLeft(dd, 10);
      aa = RIPEMD320.FF(aa, bb, cc, dd, ee, x_15,  8); cc = AbstractBlockMessageDigest.rotateLeft(cc, 10);
   // parallel round 1
      aaa = RIPEMD320.JJJ(aaa, bbb, ccc, ddd, eee, x_5 ,  8); ccc = AbstractBlockMessageDigest.rotateLeft(ccc, 10);
      eee = RIPEMD320.JJJ(eee, aaa, bbb, ccc, ddd, x_14,  9); bbb = AbstractBlockMessageDigest.rotateLeft(bbb, 10);
      ddd = RIPEMD320.JJJ(ddd, eee, aaa, bbb, ccc, x_7 ,  9); aaa = AbstractBlockMessageDigest.rotateLeft(aaa, 10);
      ccc = RIPEMD320.JJJ(ccc, ddd, eee, aaa, bbb, x_0 , 11); eee = AbstractBlockMessageDigest.rotateLeft(eee, 10);
      bbb = RIPEMD320.JJJ(bbb, ccc, ddd, eee, aaa, x_9 , 13); ddd = AbstractBlockMessageDigest.rotateLeft(ddd, 10);
      aaa = RIPEMD320.JJJ(aaa, bbb, ccc, ddd, eee, x_2 , 15); ccc = AbstractBlockMessageDigest.rotateLeft(ccc, 10);
      eee = RIPEMD320.JJJ(eee, aaa, bbb, ccc, ddd, x_11, 15); bbb = AbstractBlockMessageDigest.rotateLeft(bbb, 10);
      ddd = RIPEMD320.JJJ(ddd, eee, aaa, bbb, ccc, x_4 ,  5); aaa = AbstractBlockMessageDigest.rotateLeft(aaa, 10);
      ccc = RIPEMD320.JJJ(ccc, ddd, eee, aaa, bbb, x_13,  7); eee = AbstractBlockMessageDigest.rotateLeft(eee, 10);
      bbb = RIPEMD320.JJJ(bbb, ccc, ddd, eee, aaa, x_6 ,  7); ddd = AbstractBlockMessageDigest.rotateLeft(ddd, 10);
      aaa = RIPEMD320.JJJ(aaa, bbb, ccc, ddd, eee, x_15,  8); ccc = AbstractBlockMessageDigest.rotateLeft(ccc, 10);
      eee = RIPEMD320.JJJ(eee, aaa, bbb, ccc, ddd, x_8 , 11); bbb = AbstractBlockMessageDigest.rotateLeft(bbb, 10);
      ddd = RIPEMD320.JJJ(ddd, eee, aaa, bbb, ccc, x_1 , 14); aaa = AbstractBlockMessageDigest.rotateLeft(aaa, 10);
      ccc = RIPEMD320.JJJ(ccc, ddd, eee, aaa, bbb, x_10, 14); eee = AbstractBlockMessageDigest.rotateLeft(eee, 10);
      bbb = RIPEMD320.JJJ(bbb, ccc, ddd, eee, aaa, x_3 , 12); ddd = AbstractBlockMessageDigest.rotateLeft(ddd, 10);
      aaa = RIPEMD320.JJJ(aaa, bbb, ccc, ddd, eee, x_12,  6); ccc = AbstractBlockMessageDigest.rotateLeft(ccc, 10);
      t = aa; aa = aaa; aaa = t;
   // round 2
      ee = RIPEMD320.GG(ee, aa, bb, cc, dd, x_7 ,  7); bb = AbstractBlockMessageDigest.rotateLeft(bb, 10);
      dd = RIPEMD320.GG(dd, ee, aa, bb, cc, x_4 ,  6); aa = AbstractBlockMessageDigest.rotateLeft(aa, 10);
      cc = RIPEMD320.GG(cc, dd, ee, aa, bb, x_13,  8); ee = AbstractBlockMessageDigest.rotateLeft(ee, 10);
      bb = RIPEMD320.GG(bb, cc, dd, ee, aa, x_1 , 13); dd = AbstractBlockMessageDigest.rotateLeft(dd, 10);
      aa = RIPEMD320.GG(aa, bb, cc, dd, ee, x_10, 11); cc = AbstractBlockMessageDigest.rotateLeft(cc, 10);
      ee = RIPEMD320.GG(ee, aa, bb, cc, dd, x_6 ,  9); bb = AbstractBlockMessageDigest.rotateLeft(bb, 10);
      dd = RIPEMD320.GG(dd, ee, aa, bb, cc, x_15,  7); aa = AbstractBlockMessageDigest.rotateLeft(aa, 10);
      cc = RIPEMD320.GG(cc, dd, ee, aa, bb, x_3 , 15); ee = AbstractBlockMessageDigest.rotateLeft(ee, 10);
      bb = RIPEMD320.GG(bb, cc, dd, ee, aa, x_12,  7); dd = AbstractBlockMessageDigest.rotateLeft(dd, 10);
      aa = RIPEMD320.GG(aa, bb, cc, dd, ee, x_0 , 12); cc = AbstractBlockMessageDigest.rotateLeft(cc, 10);
      ee = RIPEMD320.GG(ee, aa, bb, cc, dd, x_9 , 15); bb = AbstractBlockMessageDigest.rotateLeft(bb, 10);
      dd = RIPEMD320.GG(dd, ee, aa, bb, cc, x_5 ,  9); aa = AbstractBlockMessageDigest.rotateLeft(aa, 10);
      cc = RIPEMD320.GG(cc, dd, ee, aa, bb, x_2 , 11); ee = AbstractBlockMessageDigest.rotateLeft(ee, 10);
      bb = RIPEMD320.GG(bb, cc, dd, ee, aa, x_14,  7); dd = AbstractBlockMessageDigest.rotateLeft(dd, 10);
      aa = RIPEMD320.GG(aa, bb, cc, dd, ee, x_11, 13); cc = AbstractBlockMessageDigest.rotateLeft(cc, 10);
      ee = RIPEMD320.GG(ee, aa, bb, cc, dd, x_8 , 12); bb = AbstractBlockMessageDigest.rotateLeft(bb, 10);
   // parallel round 2
      eee = RIPEMD320.III(eee, aaa, bbb, ccc, ddd, x_6 ,  9); bbb = AbstractBlockMessageDigest.rotateLeft(bbb, 10);
      ddd = RIPEMD320.III(ddd, eee, aaa, bbb, ccc, x_11, 13); aaa = AbstractBlockMessageDigest.rotateLeft(aaa, 10);
      ccc = RIPEMD320.III(ccc, ddd, eee, aaa, bbb, x_3 , 15); eee = AbstractBlockMessageDigest.rotateLeft(eee, 10);
      bbb = RIPEMD320.III(bbb, ccc, ddd, eee, aaa, x_7 ,  7); ddd = AbstractBlockMessageDigest.rotateLeft(ddd, 10);
      aaa = RIPEMD320.III(aaa, bbb, ccc, ddd, eee, x_0 , 12); ccc = AbstractBlockMessageDigest.rotateLeft(ccc, 10);
      eee = RIPEMD320.III(eee, aaa, bbb, ccc, ddd, x_13,  8); bbb = AbstractBlockMessageDigest.rotateLeft(bbb, 10);
      ddd = RIPEMD320.III(ddd, eee, aaa, bbb, ccc, x_5 ,  9); aaa = AbstractBlockMessageDigest.rotateLeft(aaa, 10);
      ccc = RIPEMD320.III(ccc, ddd, eee, aaa, bbb, x_10, 11); eee = AbstractBlockMessageDigest.rotateLeft(eee, 10);
      bbb = RIPEMD320.III(bbb, ccc, ddd, eee, aaa, x_14,  7); ddd = AbstractBlockMessageDigest.rotateLeft(ddd, 10);
      aaa = RIPEMD320.III(aaa, bbb, ccc, ddd, eee, x_15,  7); ccc = AbstractBlockMessageDigest.rotateLeft(ccc, 10);
      eee = RIPEMD320.III(eee, aaa, bbb, ccc, ddd, x_8 , 12); bbb = AbstractBlockMessageDigest.rotateLeft(bbb, 10);
      ddd = RIPEMD320.III(ddd, eee, aaa, bbb, ccc, x_12,  7); aaa = AbstractBlockMessageDigest.rotateLeft(aaa, 10);
      ccc = RIPEMD320.III(ccc, ddd, eee, aaa, bbb, x_4 ,  6); eee = AbstractBlockMessageDigest.rotateLeft(eee, 10);
      bbb = RIPEMD320.III(bbb, ccc, ddd, eee, aaa, x_9 , 15); ddd = AbstractBlockMessageDigest.rotateLeft(ddd, 10);
      aaa = RIPEMD320.III(aaa, bbb, ccc, ddd, eee, x_1 , 13); ccc = AbstractBlockMessageDigest.rotateLeft(ccc, 10);
      eee = RIPEMD320.III(eee, aaa, bbb, ccc, ddd, x_2 , 11); bbb = AbstractBlockMessageDigest.rotateLeft(bbb, 10);
      t = bb; bb = bbb; bbb = t;
   // round 3
      dd = RIPEMD320.HH(dd, ee, aa, bb, cc, x_3 , 11); aa = AbstractBlockMessageDigest.rotateLeft(aa, 10);
      cc = RIPEMD320.HH(cc, dd, ee, aa, bb, x_10, 13); ee = AbstractBlockMessageDigest.rotateLeft(ee, 10);
      bb = RIPEMD320.HH(bb, cc, dd, ee, aa, x_14,  6); dd = AbstractBlockMessageDigest.rotateLeft(dd, 10);
      aa = RIPEMD320.HH(aa, bb, cc, dd, ee, x_4 ,  7); cc = AbstractBlockMessageDigest.rotateLeft(cc, 10);
      ee = RIPEMD320.HH(ee, aa, bb, cc, dd, x_9 , 14); bb = AbstractBlockMessageDigest.rotateLeft(bb, 10);
      dd = RIPEMD320.HH(dd, ee, aa, bb, cc, x_15,  9); aa = AbstractBlockMessageDigest.rotateLeft(aa, 10);
      cc = RIPEMD320.HH(cc, dd, ee, aa, bb, x_8 , 13); ee = AbstractBlockMessageDigest.rotateLeft(ee, 10);
      bb = RIPEMD320.HH(bb, cc, dd, ee, aa, x_1 , 15); dd = AbstractBlockMessageDigest.rotateLeft(dd, 10);
      aa = RIPEMD320.HH(aa, bb, cc, dd, ee, x_2 , 14); cc = AbstractBlockMessageDigest.rotateLeft(cc, 10);
      ee = RIPEMD320.HH(ee, aa, bb, cc, dd, x_7 ,  8); bb = AbstractBlockMessageDigest.rotateLeft(bb, 10);
      dd = RIPEMD320.HH(dd, ee, aa, bb, cc, x_0 , 13); aa = AbstractBlockMessageDigest.rotateLeft(aa, 10);
      cc = RIPEMD320.HH(cc, dd, ee, aa, bb, x_6 ,  6); ee = AbstractBlockMessageDigest.rotateLeft(ee, 10);
      bb = RIPEMD320.HH(bb, cc, dd, ee, aa, x_13,  5); dd = AbstractBlockMessageDigest.rotateLeft(dd, 10);
      aa = RIPEMD320.HH(aa, bb, cc, dd, ee, x_11, 12); cc = AbstractBlockMessageDigest.rotateLeft(cc, 10);
      ee = RIPEMD320.HH(ee, aa, bb, cc, dd, x_5 ,  7); bb = AbstractBlockMessageDigest.rotateLeft(bb, 10);
      dd = RIPEMD320.HH(dd, ee, aa, bb, cc, x_12,  5); aa = AbstractBlockMessageDigest.rotateLeft(aa, 10);
   // parallel round 3
      ddd = RIPEMD320.HHH(ddd, eee, aaa, bbb, ccc, x_15,  9); aaa = AbstractBlockMessageDigest.rotateLeft(aaa, 10);
      ccc = RIPEMD320.HHH(ccc, ddd, eee, aaa, bbb, x_5 ,  7); eee = AbstractBlockMessageDigest.rotateLeft(eee, 10);
      bbb = RIPEMD320.HHH(bbb, ccc, ddd, eee, aaa, x_1 , 15); ddd = AbstractBlockMessageDigest.rotateLeft(ddd, 10);
      aaa = RIPEMD320.HHH(aaa, bbb, ccc, ddd, eee, x_3 , 11); ccc = AbstractBlockMessageDigest.rotateLeft(ccc, 10);
      eee = RIPEMD320.HHH(eee, aaa, bbb, ccc, ddd, x_7 ,  8); bbb = AbstractBlockMessageDigest.rotateLeft(bbb, 10);
      ddd = RIPEMD320.HHH(ddd, eee, aaa, bbb, ccc, x_14,  6); aaa = AbstractBlockMessageDigest.rotateLeft(aaa, 10);
      ccc = RIPEMD320.HHH(ccc, ddd, eee, aaa, bbb, x_6 ,  6); eee = AbstractBlockMessageDigest.rotateLeft(eee, 10);
      bbb = RIPEMD320.HHH(bbb, ccc, ddd, eee, aaa, x_9 , 14); ddd = AbstractBlockMessageDigest.rotateLeft(ddd, 10);
      aaa = RIPEMD320.HHH(aaa, bbb, ccc, ddd, eee, x_11, 12); ccc = AbstractBlockMessageDigest.rotateLeft(ccc, 10);
      eee = RIPEMD320.HHH(eee, aaa, bbb, ccc, ddd, x_8 , 13); bbb = AbstractBlockMessageDigest.rotateLeft(bbb, 10);
      ddd = RIPEMD320.HHH(ddd, eee, aaa, bbb, ccc, x_12,  5); aaa = AbstractBlockMessageDigest.rotateLeft(aaa, 10);
      ccc = RIPEMD320.HHH(ccc, ddd, eee, aaa, bbb, x_2 , 14); eee = AbstractBlockMessageDigest.rotateLeft(eee, 10);
      bbb = RIPEMD320.HHH(bbb, ccc, ddd, eee, aaa, x_10, 13); ddd = AbstractBlockMessageDigest.rotateLeft(ddd, 10);
      aaa = RIPEMD320.HHH(aaa, bbb, ccc, ddd, eee, x_0 , 13); ccc = AbstractBlockMessageDigest.rotateLeft(ccc, 10);
      eee = RIPEMD320.HHH(eee, aaa, bbb, ccc, ddd, x_4 ,  7); bbb = AbstractBlockMessageDigest.rotateLeft(bbb, 10);
      ddd = RIPEMD320.HHH(ddd, eee, aaa, bbb, ccc, x_13,  5); aaa = AbstractBlockMessageDigest.rotateLeft(aaa, 10);
      t = cc; cc = ccc; ccc = t;
   // round 4
      cc = RIPEMD320.II(cc, dd, ee, aa, bb, x_1 , 11); ee = AbstractBlockMessageDigest.rotateLeft(ee, 10);
      bb = RIPEMD320.II(bb, cc, dd, ee, aa, x_9 , 12); dd = AbstractBlockMessageDigest.rotateLeft(dd, 10);
      aa = RIPEMD320.II(aa, bb, cc, dd, ee, x_11, 14); cc = AbstractBlockMessageDigest.rotateLeft(cc, 10);
      ee = RIPEMD320.II(ee, aa, bb, cc, dd, x_10, 15); bb = AbstractBlockMessageDigest.rotateLeft(bb, 10);
      dd = RIPEMD320.II(dd, ee, aa, bb, cc, x_0 , 14); aa = AbstractBlockMessageDigest.rotateLeft(aa, 10);
      cc = RIPEMD320.II(cc, dd, ee, aa, bb, x_8 , 15); ee = AbstractBlockMessageDigest.rotateLeft(ee, 10);
      bb = RIPEMD320.II(bb, cc, dd, ee, aa, x_12,  9); dd = AbstractBlockMessageDigest.rotateLeft(dd, 10);
      aa = RIPEMD320.II(aa, bb, cc, dd, ee, x_4 ,  8); cc = AbstractBlockMessageDigest.rotateLeft(cc, 10);
      ee = RIPEMD320.II(ee, aa, bb, cc, dd, x_13,  9); bb = AbstractBlockMessageDigest.rotateLeft(bb, 10);
      dd = RIPEMD320.II(dd, ee, aa, bb, cc, x_3 , 14); aa = AbstractBlockMessageDigest.rotateLeft(aa, 10);
      cc = RIPEMD320.II(cc, dd, ee, aa, bb, x_7 ,  5); ee = AbstractBlockMessageDigest.rotateLeft(ee, 10);
      bb = RIPEMD320.II(bb, cc, dd, ee, aa, x_15,  6); dd = AbstractBlockMessageDigest.rotateLeft(dd, 10);
      aa = RIPEMD320.II(aa, bb, cc, dd, ee, x_14,  8); cc = AbstractBlockMessageDigest.rotateLeft(cc, 10);
      ee = RIPEMD320.II(ee, aa, bb, cc, dd, x_5 ,  6); bb = AbstractBlockMessageDigest.rotateLeft(bb, 10);
      dd = RIPEMD320.II(dd, ee, aa, bb, cc, x_6 ,  5); aa = AbstractBlockMessageDigest.rotateLeft(aa, 10);
      cc = RIPEMD320.II(cc, dd, ee, aa, bb, x_2 , 12); ee = AbstractBlockMessageDigest.rotateLeft(ee, 10);
   // parallel round 4
      ccc = RIPEMD320.GGG(ccc, ddd, eee, aaa, bbb, x_8 , 15); eee = AbstractBlockMessageDigest.rotateLeft(eee, 10);
      bbb = RIPEMD320.GGG(bbb, ccc, ddd, eee, aaa, x_6 ,  5); ddd = AbstractBlockMessageDigest.rotateLeft(ddd, 10);
      aaa = RIPEMD320.GGG(aaa, bbb, ccc, ddd, eee, x_4 ,  8); ccc = AbstractBlockMessageDigest.rotateLeft(ccc, 10);
      eee = RIPEMD320.GGG(eee, aaa, bbb, ccc, ddd, x_1 , 11); bbb = AbstractBlockMessageDigest.rotateLeft(bbb, 10);
      ddd = RIPEMD320.GGG(ddd, eee, aaa, bbb, ccc, x_3 , 14); aaa = AbstractBlockMessageDigest.rotateLeft(aaa, 10);
      ccc = RIPEMD320.GGG(ccc, ddd, eee, aaa, bbb, x_11, 14); eee = AbstractBlockMessageDigest.rotateLeft(eee, 10);
      bbb = RIPEMD320.GGG(bbb, ccc, ddd, eee, aaa, x_15,  6); ddd = AbstractBlockMessageDigest.rotateLeft(ddd, 10);
      aaa = RIPEMD320.GGG(aaa, bbb, ccc, ddd, eee, x_0 , 14); ccc = AbstractBlockMessageDigest.rotateLeft(ccc, 10);
      eee = RIPEMD320.GGG(eee, aaa, bbb, ccc, ddd, x_5 ,  6); bbb = AbstractBlockMessageDigest.rotateLeft(bbb, 10);
      ddd = RIPEMD320.GGG(ddd, eee, aaa, bbb, ccc, x_12,  9); aaa = AbstractBlockMessageDigest.rotateLeft(aaa, 10);
      ccc = RIPEMD320.GGG(ccc, ddd, eee, aaa, bbb, x_2 , 12); eee = AbstractBlockMessageDigest.rotateLeft(eee, 10);
      bbb = RIPEMD320.GGG(bbb, ccc, ddd, eee, aaa, x_13,  9); ddd = AbstractBlockMessageDigest.rotateLeft(ddd, 10);
      aaa = RIPEMD320.GGG(aaa, bbb, ccc, ddd, eee, x_9 , 12); ccc = AbstractBlockMessageDigest.rotateLeft(ccc, 10);
      eee = RIPEMD320.GGG(eee, aaa, bbb, ccc, ddd, x_7 ,  5); bbb = AbstractBlockMessageDigest.rotateLeft(bbb, 10);
      ddd = RIPEMD320.GGG(ddd, eee, aaa, bbb, ccc, x_10, 15); aaa = AbstractBlockMessageDigest.rotateLeft(aaa, 10);
      ccc = RIPEMD320.GGG(ccc, ddd, eee, aaa, bbb, x_14,  8); eee = AbstractBlockMessageDigest.rotateLeft(eee, 10);
      t = dd; dd = ddd; ddd = t;
   // round 5
      bb = RIPEMD320.JJ(bb, cc, dd, ee, aa, x_4 ,  9); dd = AbstractBlockMessageDigest.rotateLeft(dd, 10);
      aa = RIPEMD320.JJ(aa, bb, cc, dd, ee, x_0 , 15); cc = AbstractBlockMessageDigest.rotateLeft(cc, 10);
      ee = RIPEMD320.JJ(ee, aa, bb, cc, dd, x_5 ,  5); bb = AbstractBlockMessageDigest.rotateLeft(bb, 10);
      dd = RIPEMD320.JJ(dd, ee, aa, bb, cc, x_9 , 11); aa = AbstractBlockMessageDigest.rotateLeft(aa, 10);
      cc = RIPEMD320.JJ(cc, dd, ee, aa, bb, x_7 ,  6); ee = AbstractBlockMessageDigest.rotateLeft(ee, 10);
      bb = RIPEMD320.JJ(bb, cc, dd, ee, aa, x_12,  8); dd = AbstractBlockMessageDigest.rotateLeft(dd, 10);
      aa = RIPEMD320.JJ(aa, bb, cc, dd, ee, x_2 , 13); cc = AbstractBlockMessageDigest.rotateLeft(cc, 10);
      ee = RIPEMD320.JJ(ee, aa, bb, cc, dd, x_10, 12); bb = AbstractBlockMessageDigest.rotateLeft(bb, 10);
      dd = RIPEMD320.JJ(dd, ee, aa, bb, cc, x_14,  5); aa = AbstractBlockMessageDigest.rotateLeft(aa, 10);
      cc = RIPEMD320.JJ(cc, dd, ee, aa, bb, x_1 , 12); ee = AbstractBlockMessageDigest.rotateLeft(ee, 10);
      bb = RIPEMD320.JJ(bb, cc, dd, ee, aa, x_3 , 13); dd = AbstractBlockMessageDigest.rotateLeft(dd, 10);
      aa = RIPEMD320.JJ(aa, bb, cc, dd, ee, x_8 , 14); cc = AbstractBlockMessageDigest.rotateLeft(cc, 10);
      ee = RIPEMD320.JJ(ee, aa, bb, cc, dd, x_11, 11); bb = AbstractBlockMessageDigest.rotateLeft(bb, 10);
      dd = RIPEMD320.JJ(dd, ee, aa, bb, cc, x_6 ,  8); aa = AbstractBlockMessageDigest.rotateLeft(aa, 10);
      cc = RIPEMD320.JJ(cc, dd, ee, aa, bb, x_15,  5); ee = AbstractBlockMessageDigest.rotateLeft(ee, 10);
      bb = RIPEMD320.JJ(bb, cc, dd, ee, aa, x_13,  6); dd = AbstractBlockMessageDigest.rotateLeft(dd, 10);
   // parallel round 5
      bbb = RIPEMD320.FFF(bbb, ccc, ddd, eee, aaa, x_12,  8); ddd = AbstractBlockMessageDigest.rotateLeft(ddd, 10);
      aaa = RIPEMD320.FFF(aaa, bbb, ccc, ddd, eee, x_15,  5); ccc = AbstractBlockMessageDigest.rotateLeft(ccc, 10);
      eee = RIPEMD320.FFF(eee, aaa, bbb, ccc, ddd, x_10, 12); bbb = AbstractBlockMessageDigest.rotateLeft(bbb, 10);
      ddd = RIPEMD320.FFF(ddd, eee, aaa, bbb, ccc, x_4 ,  9); aaa = AbstractBlockMessageDigest.rotateLeft(aaa, 10);
      ccc = RIPEMD320.FFF(ccc, ddd, eee, aaa, bbb, x_1 , 12); eee = AbstractBlockMessageDigest.rotateLeft(eee, 10);
      bbb = RIPEMD320.FFF(bbb, ccc, ddd, eee, aaa, x_5 ,  5); ddd = AbstractBlockMessageDigest.rotateLeft(ddd, 10);
      aaa = RIPEMD320.FFF(aaa, bbb, ccc, ddd, eee, x_8 , 14); ccc = AbstractBlockMessageDigest.rotateLeft(ccc, 10);
      eee = RIPEMD320.FFF(eee, aaa, bbb, ccc, ddd, x_7 ,  6); bbb = AbstractBlockMessageDigest.rotateLeft(bbb, 10);
      ddd = RIPEMD320.FFF(ddd, eee, aaa, bbb, ccc, x_6 ,  8); aaa = AbstractBlockMessageDigest.rotateLeft(aaa, 10);
      ccc = RIPEMD320.FFF(ccc, ddd, eee, aaa, bbb, x_2 , 13); eee = AbstractBlockMessageDigest.rotateLeft(eee, 10);
      bbb = RIPEMD320.FFF(bbb, ccc, ddd, eee, aaa, x_13,  6); ddd = AbstractBlockMessageDigest.rotateLeft(ddd, 10);
      aaa = RIPEMD320.FFF(aaa, bbb, ccc, ddd, eee, x_14,  5); ccc = AbstractBlockMessageDigest.rotateLeft(ccc, 10);
      eee = RIPEMD320.FFF(eee, aaa, bbb, ccc, ddd, x_0 , 15); bbb = AbstractBlockMessageDigest.rotateLeft(bbb, 10);
      ddd = RIPEMD320.FFF(ddd, eee, aaa, bbb, ccc, x_3 , 13); aaa = AbstractBlockMessageDigest.rotateLeft(aaa, 10);
      ccc = RIPEMD320.FFF(ccc, ddd, eee, aaa, bbb, x_9 , 11); eee = AbstractBlockMessageDigest.rotateLeft(eee, 10);
      bbb = RIPEMD320.FFF(bbb, ccc, ddd, eee, aaa, x_11, 11); ddd = AbstractBlockMessageDigest.rotateLeft(ddd, 10);
      t = ee; ee = eee; eee = t;

   // combine results
      state[0] += aa;
      state[1] += bb;
      state[2] += cc;
      state[3] += dd;
      state[4] += ee;
      state[5] += aaa;
      state[6] += bbb;
      state[7] += ccc;
      state[8] += ddd;
      state[9] += eee;
      }

   @Override
   protected void coreInit() {
      int[] state = this.getState();
      state[0] = 0x67452301;
      state[1] = 0xefcdab89;
      state[2] = 0x98badcfe;
      state[3] = 0x10325476;
      state[4] = 0xc3d2e1f0;
      state[5] = 0x76543210;
      state[6] = 0xfedcba98;
      state[7] = 0x89abcdef;
      state[8] = 0x01234567;
      state[9] = 0x3c2d1e0f;
      }

   }

